home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 10 / FM Towns Free Software Collection 10.iso / ms_dos / tool / athena / athena.c next >
Text File  |  1995-02-18  |  26KB  |  1,035 lines

  1. /*
  2.  
  3. 8086|Printman/TEXT 'Athena' Version 1.00a
  4.  With 8086|Printman Library Version 1.20
  5.  
  6. Copyright (c) 1995 Delmonta
  7.  
  8. コンパイル時の注意:
  9.     (1)8086|Printman Library Ver1.20以上を必ずリンクすること
  10.     (2)クォートで括った文字列を分解せずにmainに渡す
  11.        スタートアップルーチンを必ずリンクすること
  12.  
  13. 参考:
  14.     (1)浮動小数点演算は使っていない。printfなどは小数に対応していない
  15.        サブセット版をリンクしてもよい。
  16. */
  17.  
  18. /*------------------------ヘッダのインクルード-------------------------------*/
  19. #include<stdio.h>
  20. #include<stdlib.h>
  21. #include<string.h>
  22.  
  23. #include<jctype.h>
  24. #include<jstring.h>
  25.  
  26. #include<DEL_PRN.H>
  27. /*---------------------------------マクロ関数--------------------------------*/
  28. #ifdef    DEBUG
  29.     #define    DEBUGPRINT(f)    printf f
  30. #else
  31.     #define    DEBUGPRINT(f)
  32. #endif
  33.  
  34. #define    BYTEWIDTH(c)    (1+((c)>=256))        /* cが全角なら2、半角なら1  */
  35. #define    CEIL(a,b)    (((a)+(b)-1)/(b))    /* aをbで割り端数を切り上げ */
  36. #ifndef    DOT2MM
  37.     #define    DOT2MM(n)    ((n)*127L/900)    /* ドット数からmmへの換算   */
  38. #endif
  39. /*----------------------------------型と定数---------------------------------*/
  40. typedef    unsigned short    ushort;
  41.  
  42. #define    LINE_MAXCHARNUM    256        /* 1行の最大の文字数          */
  43. #define    HEADER_YSPACE    36        /* ヘッダの後にあけるドット数 */
  44. #define    FOOTER_YSPACE    36        /* フッタの後にあけるドット数 */
  45.  
  46. static    const    int    Papersize[2][8] =
  47. {
  48.     {1189, 841,594,420,297,210,148,105},    /* A0~A6 */
  49.     {1456,1030,728,515,364,257,182,128},    /* B0~B6 */
  50. };
  51.  
  52. static    const    char    Lastillegal_tbl[] = 
  53.     "‘“(〔[{〈《「『【<`([{「<";
  54. static    const    char    Firstillegal_tbl[] =
  55.     "゛゜、。,.・:;?!’”)〕]}〉》」』】>゙゚、。,.・;:?!')]}」>/"
  56.     "ぁぃぅぇぉゃゅょっァィゥェォャュョッゎヮヵヶァィゥェォャュョッ";
  57. /*--------------------------------変数---------------------------------------*/
  58. static    char    *Pathname;    /* 現在出力中のファイルのフルパス*/
  59. static    char    *Filename;    /* 同           パス名を除く部分 */
  60. static    int    Pagenum;    /* ページ番号                    */
  61. static    int    Linenum;    /* 現在Linebufにたまっている行数 */
  62.  
  63. extern    enum PRNBIOS    Prn_machine = PRNBIOS_TOWNS;    /*     (-C) */
  64. extern    enum PRNMODE    Prn_mode = PRNMODE_ESCP;    /*     (-P) */
  65.  
  66. static    struct    /* コマンドラインから受け取ったオプション ; 単位は基本的にmm */
  67. {
  68.     struct    {int x,y;}    papersize;    /* 用紙サイズ  (-S) */
  69.     struct    {int u,l;}    pmargin;    /* 物理マージン(-L) */
  70.     struct    {int u,l,r,d;}    lmargin;    /* 論理マージン(-M) */
  71.     char            *header;    /* ヘッダ      (-H) */
  72.     char            *footer;    /* フッタ      (-F) */
  73.     struct    {int num,space;}block;        /* 段組        (-K) */
  74.     struct    {int x,y;}    charnum;    /* 段の字数    (-N) */
  75.     struct    {int s,e;int n;}area;        /* 出力する範囲(-A) */
  76.  
  77.     int            tabstop;    /* タブ幅      (-T) */
  78.     int            istategaki;    /* 縦書きの指定(-W) */
  79.  
  80.     int            tostdout;    /* 標準出力へ (-P!) */
  81. } Options = {{182,257},{9,3},{20,10,10,20},NULL,NULL,{1,10},{80,40},{1,9999,0},
  82.                         8,0, 0};
  83.  
  84. static    struct    /* 変換した書式パラメータ ; 単位は全てドット=1/180インチ */
  85. {
  86.     struct    {int x,y;}    blocksize;    /* 段の大きさ               */
  87.     int            xwidth;        /* 印刷可能領域の横幅       */
  88.     struct    {int u,l;}    margin;        /* 物理マージンを差引いたマージン */
  89.     int            blockspace;    /* 段間スペース             */
  90. } Format;
  91.  
  92. static    struct    LINEBUF
  93. {
  94.     int    charnum;
  95.     int    bytenum;
  96.     ushort    *buf;
  97. } *Linebuf;
  98. /*****************************************************************************/
  99. /*                  8086|Printman Libraryに直接関係する部分                  */
  100. /*****************************************************************************/
  101. /*-------------------------------エラー処理----------------------------------*/
  102. extern    enum PRNHERR    prn_harderr(void)
  103. {
  104.     char    c;
  105.  
  106.     fputs("\nプリンタエラーです.\n中止<A>, 再試行<R>, 無視<I>?",stderr);
  107. rep:
  108.     c = getch();
  109.     switch(c)
  110.     {
  111.     case 'A':
  112.     case 'a':
  113.         fputs("A\n",stderr);
  114.         exit(1);
  115.     case 'R':
  116.     case 'r':
  117.         fputs("R\n",stderr);
  118.         return PRNHERR_RETRY;
  119.     case 'I':
  120.     case 'i':
  121.         fputs("I\n",stderr);
  122.         return PRNHERR_IGNORE;
  123.     default:
  124.         putc('\a',stderr);
  125.         goto rep;
  126.     }
  127. }
  128. /*--------------------------------改行処理-----------------------------------*/
  129. /* prn_linefeed()+MSXプリンタでは一度に99/180インチまでしか改行できない     */
  130. /* (ESC/Pは255/180、PC-PRでは99/120)ので、それより大きい場合は複数回に分割し */
  131. /* て処理する                                                                */
  132. /*---------------------------------------------------------------------------*/
  133. static    void    linefeed(int n)
  134. {
  135.     while    (n>=64)
  136.     {
  137.         prn_linefeed(64);
  138.         n -= 64;
  139.     }
  140.  
  141.     prn_linefeed(n);
  142. }
  143. /*****************************************************************************/
  144. /*                      文字列処理・ファイル入力                             */
  145. /*****************************************************************************/
  146. /*----------------------------ファイル入力-----------------------------------*/
  147. static    int    Ungetc_num = 0;
  148. static    ushort    Ungetc_buf[LINE_MAXCHARNUM+1];    /* xungetc()用のバッファ */
  149. static    FILE    *Fp;
  150.  
  151. ushort    xgetc(void)
  152. {
  153.     ushort    c;
  154.  
  155.     if    (Ungetc_num)
  156.         return Ungetc_buf[--Ungetc_num];
  157.  
  158.     c = getc(Fp);
  159.     if    (iskanji(c))
  160.         return (c<<8) + getc(Fp);
  161.     else
  162.         return c;
  163. }
  164.  
  165. void    xungetc(ushort c)
  166. {
  167.     Ungetc_buf[Ungetc_num++] = c;
  168. }
  169. /*----------------------行末禁則文字かどうかの判定---------------------------*/
  170. static    int    islastillegal(ushort c)
  171. {
  172.     char    buf[3];
  173.  
  174.     if    (BYTEWIDTH(c)==2)
  175.     {
  176.         buf[0] = c>>8;
  177.         buf[1] = c;
  178.         buf[2] = '\0';
  179.     }
  180.     else
  181.     {
  182.         buf[0] = c;
  183.         buf[1] = '\0';
  184.     }
  185.  
  186.     return jstrstr(Lastillegal_tbl,buf)!=NULL;
  187. }
  188. /*----------------------行頭禁則文字かどうかの判定---------------------------*/
  189. static    int    isfirstillegal(ushort c)
  190. {
  191.     char    buf[3];
  192.  
  193.     if    (BYTEWIDTH(c)==2)
  194.     {
  195.         buf[0] = c>>8;
  196.         buf[1] = c;
  197.         buf[2] = '\0';
  198.     }
  199.     else
  200.     {
  201.         buf[0] = c;
  202.         buf[1] = '\0';
  203.     }
  204.  
  205.     return jstrstr(Firstillegal_tbl,buf)!=NULL;
  206. }
  207. /*****************************************************************************/
  208. /*                             プリンタ出力                                  */
  209. /*****************************************************************************/
  210. /*----------------------パラメータを表示して確認をとる-----------------------*/
  211. /* 一部に、一度ドット数に換算してからさらにもう一度mmに直しているために二重の*/
  212. /* 誤差が発生している部分がある                                              */
  213. /*---------------------------------------------------------------------------*/
  214. static    void    showoption(void)
  215. {
  216.  
  217.     fputs("機種設定     : ",stderr);
  218.     if    (Options.tostdout)    fputs("標準出力へ出力\n",stderr);
  219.     else
  220.     {
  221.         switch    (Prn_machine)
  222.         {
  223.         case PRNBIOS_NEC98:    fputs("PC-9800"  ,stderr); break;
  224.         case PRNBIOS_TOWNS:    fputs("FMR/TOWNS",stderr); break;
  225.         case PRNBIOS_IBMPC:    fputs("DOS/V"    ,stderr); break;
  226.         case PRNBIOS_J3100:    fputs("J-3100/AX",stderr); break;
  227.         }
  228.  
  229.         fprintf(stderr," + ");
  230.  
  231.         switch    (Prn_mode)
  232.         {
  233.         case PRNMODE_ESCP:    fputs("ESC/P-J84",stderr); break;
  234.         case PRNMODE_MSX:    fputs("MSX"      ,stderr); break;
  235.         case PRNMODE_PCPR:    fputs("PC-PR201H",stderr); break;
  236.         case PRNMODE_FMPR:    fputs("FMPR"     ,stderr); break;
  237.         }
  238.  
  239.         putc('\n',stderr);
  240.     }
  241.  
  242.     fprintf(stderr,"\n印刷するファイル : %s\n",Pathname);
  243.  
  244.     fprintf(stderr, "物理マージン : 上%dmm  左%dmm\n"
  245.             "\n"
  246.             "用紙サイズ   : 横%dmm×縦%dmm\n"
  247.             "論理マージン : 上%dmm  左%dmm  右%dmm 下%dmm\n"
  248.  
  249.             "印字方向     : %s書き\n"
  250.             "出力する範囲 : %d~%dページ(ページ番号 %+d)\n"
  251.  
  252.             "1字の幅      : 全角あたり  横%d×縦%dドット\n"
  253.             "字詰め       : %d字×%d行\n"
  254.             "段組         : %d段(段幅%dmm",
  255.  
  256.         Options.pmargin  .u, Options.pmargin  .l,
  257.         Options.papersize.x, Options.papersize.y,
  258.         Options.lmargin  .u, Options.lmargin  .l,
  259.         Options.lmargin  .r, Options.lmargin  .d,
  260.  
  261.         (Options.istategaki ? "縦" : "横" ),
  262.         Options.area.s,Options.area.e,Options.area.n,
  263.  
  264.         Format.blocksize.x*2/Options.charnum.x,
  265.         Format.blocksize.y  /Options.charnum.y,
  266.  
  267.         Options.charnum.x, Options.charnum.y,
  268.         Options.block.num, (int)DOT2MM(Format.blocksize.x));
  269.  
  270.     if    (Options.block.num>=2)
  271.         fprintf(stderr," 段間%dmm",Options.block.space);
  272.  
  273.     fputs(")\n\nヘッダ       : ",stderr);
  274.     if    (Options.header==NULL)
  275.         fputs("(なし)",stderr);
  276.     else
  277.         fprintf(stderr,"%s",Options.header);
  278.  
  279.     fputs("\nフッタ       : ",stderr);
  280.     if    (Options.footer==NULL)
  281.         fputs("(なし)",stderr);
  282.     else
  283.         fprintf(stderr,"%s",Options.footer);
  284.  
  285.     fputs("\n\nこれでよろしいですか(y/n)",stderr);
  286.  
  287.     while    (1)
  288.     {
  289.         switch    (getch())
  290.         {
  291.         case 'Y':
  292.         case 'y':
  293.         case '\r':
  294.         case '\n':
  295.             fputs("Y\n",stderr);
  296.             return;
  297.         case 'N':
  298.         case 'n':
  299.         case '\3':
  300.             fputs("N\n",stderr);
  301.             exit(1);
  302.         default:
  303.             putc('\a',stderr);
  304.         }
  305.     }
  306. }
  307. /*--------------------------------初期化-------------------------------------*/
  308. static    void    init(char *filename)
  309. {
  310.     Pathname = filename;    /* strdupは不要 */
  311.  
  312.     Filename = jstrrchr(Pathname,'\\');
  313.     if    (Filename==NULL)
  314.     {
  315.         if    (Pathname[1]==':')
  316.             Filename = Pathname+2;
  317.         else
  318.             Filename = Pathname;
  319.     }
  320.     else
  321.         Filename++;
  322.  
  323.     Fp = fopen(filename,"r");
  324.     if    (Fp==NULL)
  325.     {
  326.         fprintf(stderr,"ファイル %s がオープンできません\n",filename);
  327.         exit(1);
  328.     }
  329.  
  330.     Pagenum = 1;
  331.  
  332.     Linebuf = (struct LINEBUF *)malloc
  333.         (sizeof(struct LINEBUF)*Options.charnum.y*Options.block.num);
  334.     if    (Linebuf==NULL)
  335.     {
  336.         fprintf(stderr,"メモリ不足です\n");
  337.         exit(1);
  338.     }
  339.  
  340.     if    (Options.tostdout)
  341.     {
  342.         Format.xwidth =   Options.charnum.x*Options.block.num
  343.                 + Options.block.space*(Options.block.num-1);
  344.         return;
  345.     }
  346.     else    /* !Options.tostdout */
  347.     {
  348.         if    (Options.pmargin.u>Options.lmargin.u ||
  349.              Options.pmargin.l>Options.lmargin.l)
  350.         {
  351.             fprintf(stderr,"論理マージンが物理マージンより小さくなっています.\n");
  352.             exit(1);
  353.         }
  354.  
  355.         Format.blocksize.x = MM2DOTS(Options.papersize.x
  356.             - Options.lmargin.l - Options.lmargin.r
  357.             - (Options.block.num-1)*Options.block.space)
  358.             / Options.block.num;
  359.  
  360.         Format.blocksize.y = MM2DOTS(Options.papersize.y
  361.             - Options.lmargin.u - Options.lmargin.d );
  362.  
  363.         if    (Format.blocksize.x<=0 || Format.blocksize.y<=0)
  364.         {
  365.             fprintf(stderr,"マージンが多すぎて印刷可能範囲がありません.\n");
  366.             exit(1);
  367.         }
  368.  
  369.         Format.xwidth = MM2DOTS(Options.papersize.x
  370.             - Options.lmargin.l - Options.lmargin.r);
  371.  
  372.         Format.blockspace=MM2DOTS(Options.block.space);
  373.         Format.margin.u  =MM2DOTS(Options.lmargin.u-Options.pmargin.u);
  374.         Format.margin.l  =MM2DOTS(Options.lmargin.l-Options.pmargin.l);
  375.  
  376.         if    (Options.header!=NULL)
  377.             Format.blocksize.y -= HEADER_YSPACE+24;
  378.         if    (Options.footer!=NULL)
  379.             Format.blocksize.y -= FOOTER_YSPACE+24;
  380.  
  381.         showoption();
  382.     }
  383. }
  384. /*--------------------------ヘッダの特殊コードの処理-------------------------*/
  385. /* 返した内容は次に呼び出すまで有効。返した領域を自由に書き換えてもよい      */
  386. /*---------------------------------------------------------------------------*/
  387. static    char    *compile_header(char *header)
  388. {
  389.     static    char    buf[256];
  390.     char        *p = buf;
  391.     char        c;
  392.  
  393.     while    ((c=*header++)!='\0')
  394.     {
  395.         if    (c!='%')
  396.         {
  397.             *p++ = c;
  398.             if    (iskanji(c))
  399.                 *p++ = *header++;
  400.  
  401.             continue;
  402.         }
  403.  
  404.         switch    (c=toupper(*header++))
  405.         {
  406.         case 'P': p += sprintf(p,"%s",Pathname);        break;
  407.         case 'F': p += sprintf(p,"%s",Filename);        break;
  408.         case 'N': p += sprintf(p,"%d",Pagenum+Options.area.n);    break;
  409.         default : *p++ = c;
  410.         }
  411.     }
  412.     *p = '\0';
  413.     return buf;
  414. }
  415. /*-----------------------ページの出力(標準出力へ)----------------------------*/
  416. static    void    putpage_to_stdout(void)
  417. {
  418.     int    i,j,k;    /* ループカウンタ          */
  419.     int    line;    /* putpage()のコメント参照 */
  420.  
  421.     line = CEIL(Linenum,Options.block.num);
  422.  
  423.     if    (Options.header!=NULL)
  424.     {
  425.         char    *p = compile_header(Options.header);
  426.  
  427.         printf("%*s%s\n\n",(Format.xwidth-strlen(p))/2,"",p);
  428.     }
  429.  
  430.     for    (i=0 ; i<line ; i++)
  431.     {
  432.         for    (j=0 ; ; )
  433.         {
  434.             int    n=0;
  435.  
  436.             struct    LINEBUF    buf;
  437.  
  438.             if    (j*line+i>=Linenum)
  439.             {
  440.                 printf("%*s",Options.charnum.x,"");
  441.                 goto next;
  442.             }
  443.  
  444.             buf = Linebuf[j*line+i];
  445.  
  446.             for    (k=0 ; k<buf.charnum ; k++)
  447.             {
  448.                 n += BYTEWIDTH(buf.buf[k]);
  449.  
  450.                 if    (BYTEWIDTH(buf.buf[k])==2)
  451.                     putchar(buf.buf[k]>>8);
  452.  
  453.                 putchar((unsigned char)buf.buf[k]);
  454.             }
  455.  
  456.             free(buf.buf);
  457.  
  458.         next:
  459.             if    (++j==Options.block.num)
  460.                 break;
  461.  
  462.             printf("%*s",Options.charnum.x-n+Options.block.space,"");
  463.         }
  464.         putchar('\n');
  465.     }
  466.  
  467.     for    (i=line ; i<Options.charnum.y ; i++)
  468.         putchar('\n');
  469.  
  470.     if    (Options.footer!=NULL)
  471.     {
  472.         char    *p = compile_header(Options.footer);
  473.  
  474.         printf("\n%*s%s\n",(Format.xwidth-strlen(p))/2,"",p);
  475.     }
  476.  
  477.     for    (i=0 ; i<Options.lmargin.d ; i++)
  478.         putchar('\n');
  479.  
  480.     Pagenum++;
  481.     Linenum = 0;
  482. }
  483. /*-----------------------ページの出力(プリンタへ)----------------------------*/
  484. static    void    putpage(void)
  485. {
  486.     int    i,j,k;        /* ループカウンタ */
  487.     int    line;        /* 印刷する物理行数;ceil(バッファの行数/段数)*/
  488.     int    feeded = 0;    /* これまでに出力された改行の量 */
  489.  
  490.     if    (Pagenum<Options.area.s || Pagenum>Options.area.e)
  491.     {
  492.         for    (i=0 ; i<Linenum ; i++)
  493.             free(Linebuf[i].buf);
  494.  
  495.         goto end_of_output;
  496.     }
  497.  
  498.     if    (Options.tostdout)
  499.     {
  500.         putpage_to_stdout();
  501.         return;
  502.     }
  503.  
  504.     while    (kbhit())
  505.         ;
  506.  
  507.     fprintf(stderr,"%dページを印刷します 何かキーを押してください",Pagenum);    if    (getch()=='\3')
  508.     {
  509.         fputs("^C\n",stderr);
  510.         exit(0);
  511.     }
  512.     if    (Pagenum==1 || Pagenum==Options.area.s)
  513.         prn_init();
  514.  
  515.     if    (Options.istategaki)
  516.         prn_tategaki(PRNTATE_NOHALF);
  517.  
  518.     fprintf(stderr,"\n%dページを印刷中です\n",Pagenum);
  519.  
  520.     linefeed(Format.margin.u);
  521.     if    (Options.header!=NULL)
  522.     {
  523.         char    *s = compile_header(Options.header);
  524.  
  525.         prn_setcarridge(Format.margin.l + 
  526.             (Format.xwidth - strlen(s)*PRN_CHRWIDTH/2)/2);
  527.  
  528.         prn_putstr(s);
  529.         linefeed(HEADER_YSPACE+24);
  530.     }
  531.  
  532.     line = CEIL(Linenum,Options.block.num);
  533.     for    (i=0 ; i<line ; i++)
  534.     {
  535.         int    pos;
  536.  
  537.         for    (j=0,pos=Format.margin.l ; j<Options.block.num ; 
  538.             j++ , pos += Format.blocksize.x+Format.blockspace)
  539.         {
  540.             struct    LINEBUF    buf;
  541.             int        n;    /* 出力されたバイト数 */
  542.  
  543.             if    (j*line+i>=Linenum)
  544.                 continue;
  545.  
  546.             buf = Linebuf[j*line+i];
  547.             n   = 0;
  548.  
  549.             for    (k=0 ; k<buf.charnum ; k++)
  550.             {
  551.                 prn_setcarridge(pos + (long)n*
  552.                     Format.blocksize.x/buf.bytenum);
  553.  
  554.                 prn_putchar(buf.buf[k]);
  555.                 n += BYTEWIDTH(buf.buf[k]);
  556.             }
  557.  
  558.             free(buf.buf);
  559.         }
  560.  
  561.                 /* 丸め誤差が出ないように面倒な計算をする */
  562.                 /* longで計算するのはオーバーフロー防止のため   */
  563.         j = (i+1L)*(long)Format.blocksize.y/Options.charnum.y;
  564.         linefeed(j-feeded);
  565.         feeded = j;
  566.     }
  567.  
  568.     linefeed(Format.blocksize.y - feeded);
  569.  
  570.     if    (Options.footer!=NULL)
  571.     {
  572.         char    *s = compile_header(Options.footer);
  573.  
  574.         linefeed(FOOTER_YSPACE);
  575.  
  576.         prn_setcarridge(Format.margin.l + 
  577.             (Format.xwidth - strlen(s)*PRN_CHRWIDTH/2)/2);
  578.  
  579.         prn_putstr(s);
  580.         linefeed(24);
  581.     }
  582.  
  583.     prn_tategaki(PRNTATE_NONE);
  584.     prn_formfeed();
  585. end_of_output:
  586.     Pagenum++;
  587.     Linenum = 0;
  588. }
  589. /*----------------------最終ページの出力 & 後始末----------------------------*/
  590. static    void    lastpage(void)
  591. {
  592.     if    (Linenum)
  593.         putpage();
  594.     free(Linebuf);
  595.     fclose(Fp);
  596. }
  597. /*------------------------行単位でバッファに格納-----------------------------*/
  598. static    void    putout(ushort *buf,int charnum,int bytenum,int islf)
  599. {
  600.     static    int    nocheck = 0;    /* その行だけ禁則処理を行わないフラグ */
  601.  
  602.     ushort    c,nextchar;
  603.  
  604.     if    (islf)
  605.     {
  606.         bytenum = Options.charnum.x;
  607.         goto output_main;
  608.     }
  609.  
  610.     nextchar = xgetc();
  611.     if    (nextchar=='\n' || nextchar==EOF)
  612.         goto output_main;
  613.  
  614.     if    (nocheck)
  615.     {
  616.         nocheck = 0;
  617.         xungetc(nextchar);
  618.         goto output_main;
  619.     }
  620.  
  621.     while    (bytenum>=Options.charnum.x/2)    /* while(bytenum)とすべきか? */
  622.     {
  623.         c = buf[charnum-1];
  624.         if    (islastillegal(c) || isfirstillegal(nextchar))
  625.         {
  626.             charnum--;
  627.             xungetc(nextchar);
  628.             nextchar = c;
  629.             bytenum -= BYTEWIDTH(c);
  630.         }
  631.         else
  632.         {
  633.             xungetc(nextchar);
  634.             goto output_main;
  635.         }
  636.     }
  637.  
  638.     /* 禁則処理で長さが半分未満になった場合 */
  639.     xungetc(nextchar);
  640.     while    (charnum)
  641.         xungetc(buf[--charnum]);
  642.     nocheck = 1;
  643.     return;
  644.  
  645. output_main:
  646.     if    (charnum)
  647.     {
  648.         Linebuf[Linenum].buf = (ushort*)malloc(charnum*sizeof(ushort));
  649.         if    (Linebuf[Linenum].buf==NULL)
  650.         {
  651.             fprintf(stderr,"メモリ不足です\n");
  652.             exit(1);
  653.         }
  654.  
  655.         memcpy(Linebuf[Linenum].buf,buf,charnum*sizeof(ushort));
  656.     }
  657.  
  658.     Linebuf[Linenum].charnum = charnum;
  659.     Linebuf[Linenum].bytenum = bytenum;
  660.  
  661.     if    (++Linenum==Options.block.num*Options.charnum.y)
  662.         putpage();
  663. }
  664. /*---------------------プリンタ出力のメインルーチン--------------------------*/
  665. static    void    xmain(char *filename)
  666. {
  667.     int    charnum = 0;    /* 現在入力中の文字列の文字数 */
  668.     int    bytenum = 0;    /* 現在入力中の文字列のバイト数 */
  669.  
  670.     ushort    buf[LINE_MAXCHARNUM];
  671.     ushort    c;
  672.  
  673.     init(filename);
  674.  
  675.     while    ((c=xgetc())!=EOF)
  676.     {
  677.         if    (c=='\n')
  678.         {
  679.             putout(buf,charnum,bytenum,1);
  680.             charnum = bytenum = 0;
  681.             continue;
  682.         }
  683.         else if    (c=='\t')
  684.         {
  685.             int    n = bytenum + Options.tabstop - 
  686.                     bytenum%Options.tabstop;
  687.  
  688.             if    (n>Options.charnum.x)
  689.                 n = Options.charnum.x;
  690.  
  691.             for    ( ; bytenum<n ; bytenum++)
  692.                 buf[charnum++] = ' ';
  693.  
  694.             if    (n==Options.charnum.x)
  695.             {
  696.                 putout(buf,charnum,bytenum,1);
  697.                 charnum=bytenum=0;
  698.                 continue;
  699.             }
  700.         }
  701.         else if    (BYTEWIDTH(c)==1 && iscntrl(c))
  702.             continue;
  703.         else
  704.         {
  705.             buf[charnum++] = c;
  706.             bytenum += BYTEWIDTH(c);
  707.         }
  708.  
  709.         if    (bytenum>=Options.charnum.x)
  710.         {
  711.             if    (bytenum>Options.charnum.x)
  712.             {
  713.                 xungetc(buf[--charnum]);
  714.                 bytenum -= 2;    /* はみ出すのは全角のみ */
  715.             }
  716.  
  717.             putout(buf,charnum,bytenum,0);
  718.             charnum = bytenum = 0;
  719.         }
  720.     }
  721.  
  722.     if    (charnum)
  723.         putout(buf,charnum,bytenum,1);
  724.  
  725.     lastpage();
  726. }
  727. /*****************************************************************************/
  728. /*                              オプションの解析                             */
  729. /*****************************************************************************/
  730. /*--------------------------S(用紙サイズ)オプション--------------------------*/
  731. static    int    option_s(char *s)
  732. {
  733.     int    a,b;
  734.  
  735.     if    (isdigit(s[0]))
  736.     {
  737.         return sscanf(s,"%u,%u",&Options.papersize.x,
  738.                     &Options.papersize.y)==2;
  739.     }
  740.  
  741.     a = toupper(s[0])-'A';
  742.     if    (a!=0 && a!=1)
  743.         return 0;
  744.  
  745.     b = s[1]-'0';
  746.     if    (b<0 || 6
  747. <b)
  748.         return 0;
  749.  
  750.     if    (s[2]=='R' || s[2]=='r' || s[2]=='\0')
  751.     {
  752.         Options.papersize.x = Papersize[a][b+1];
  753.         Options.papersize.y = Papersize[a][b  ];
  754.     }
  755.     else if    (s[2]=='L' || s[2]=='l')
  756.     {
  757.         Options.papersize.x = Papersize[a][b  ];
  758.         Options.papersize.y = Papersize[a][b+1];
  759.     }
  760.     else
  761.         return 0;
  762.  
  763.     return 1;
  764. }
  765. /*----------------------C(コンピュータの機種)オプション----------------------*/
  766. static    int    option_c(char *s)
  767. {
  768.     if    (*s=='N' || *s=='n' || *s=='9')    Prn_machine=PRNBIOS_NEC98;
  769.     else if    (*s=='F' || *s=='f')        Prn_machine=PRNBIOS_TOWNS;
  770.     else if (*s=='I' || *s=='i')        Prn_machine=PRNBIOS_IBMPC;
  771.     else if    (*s=='J' || *s=='j' || *s=='A' || *s=='a')
  772.                          Prn_machine=PRNBIOS_J3100;
  773.     else
  774.         return 0;
  775.  
  776.     return 1;
  777. }
  778. /*-------------------------P(プリンタの機種)オプション-----------------------*/
  779. static    int    option_p(char *s)
  780. {
  781.     if    (*s=='!')
  782.     {
  783.         Options.tostdout  = 1;
  784.         Options.lmargin.d = 1;
  785.         return 1;
  786.     }
  787.  
  788.     Options.tostdout = 0;
  789.  
  790.     if    (*s=='E' || *s=='e')    Prn_mode=PRNMODE_ESCP;
  791.     else if    (*s=='M' || *s=='m')    Prn_mode=PRNMODE_MSX;
  792.     else if    (*s=='P' || *s=='p')    Prn_mode=PRNMODE_PCPR;
  793.     else if    (*s=='F' || *s=='f')    Prn_mode=PRNMODE_FMPR;
  794.     else
  795.         return 0;
  796.  
  797.     return 1;
  798. }
  799. /*----------------------------?(ヘルプ)オプション----------------------------*/
  800. /* このオプションの出力は通常のstderrではなくstdoutにする(リダイレクトできる */
  801. /* ように)                                                                   */
  802. /*---------------------------------------------------------------------------*/
  803. static    void    option_help(void)
  804. {
  805.     printf(    "書式 : ATHENA [オプション] ファイル名\n"
  806.         "\n"
  807.         "オプション:\n"
  808.         "     -C{NEC|FM|IBM|J31|AX}           コンピュータの機種\n"
  809.         "     -P{ESCP|MSX|PCPR|FMPR}          プリンタの機種\n"
  810.         "     -S横幅,縦幅/-S{A|B}{3|4|5|6}[L] 用紙サイズ\n"
  811.         "     -L上,左  -M上,左,右,下          物理マージン,論理マージン\n"
  812.         "     -K段数,段間スペース             段組の指定\n"
  813.         "     -N横,縦                         段の字数\n"
  814.         "     -T数値                          タブ幅\n"
  815.         "     -W[{0|1}]                       縦書きの指定\n"
  816.         "     -H\"ヘッダ\",-F\"フッタ\"           ヘッダ,フッタ\n"
  817.         "     -A開始頁,終了頁[,頁番号オフセット]   印刷する範囲の指定\n"
  818.         "\n"
  819.         "     @ファイル名                     パラメータをファイルで指定\n"
  820.         "\n"
  821.         "オプションでの長さの指定はmm単位です\n");
  822.     exit(0);
  823. }
  824. /*-----------------------オプション解析のメインルーチン----------------------*/
  825. static    void    option(char *s)
  826. {
  827.     switch    (toupper(s[1]))
  828.     {
  829.     case 'C':
  830.         if    (!option_c(s+2))
  831.             goto error;
  832.         break;
  833.     case 'P':
  834.         if    (!option_p(s+2))
  835.             goto error;
  836.         break;
  837.     case 'S':
  838.         if    (!option_s(s+2))
  839.             goto error;
  840.         break;
  841.  
  842.     case 'L':
  843.         sscanf(s+2,"%d,%d",&Options.pmargin.u,&Options.pmargin.l);
  844.         break;
  845.     case 'M':
  846.         sscanf(s+2,"%u,%u,%u,%u",&Options.lmargin.u,
  847.             &Options.lmargin.l,&Options.lmargin.r,&Options.lmargin.d);
  848.         break;
  849.     case 'H':
  850.         if    (Options.header!=NULL)
  851.             free(Options.header);
  852.  
  853.         if    (s[2]=='\0')
  854.             Options.header = NULL;
  855.         else if    ((Options.header=strdup(s+2))==NULL)
  856.             goto nomem;
  857.         break;
  858.     case 'F':
  859.         if    (Options.footer!=NULL)
  860.             free(Options.footer);
  861.  
  862.         if    (s[2]=='\0')
  863.             Options.footer = NULL;
  864.         else if    ((Options.footer=strdup(s+2))==NULL)
  865.             goto nomem;
  866.         break;
  867.     case 'K':
  868.         sscanf(s+2,"%u,%u",&Options.block.num,&Options.block.space);
  869.         break;
  870.     case 'N':
  871.         sscanf(s+2,"%u,%u",&Options.charnum.x,&Options.charnum.y);
  872.         break;
  873.     case 'A':
  874.         sscanf(s+2,"%u,%u,%d",&Options.area.s,&Options.area.e,
  875.                         &Options.area.n);
  876.         if    (Options.area.s>Options.area.e)
  877.             goto error;
  878.  
  879.         break;
  880.     case 'T':
  881.         sscanf(s+2,"%u",&Options.tabstop);
  882.         break;
  883.     case 'W':
  884.         if    (s[2]=='1' || s[2]=='\0') /* 単に-Wは-W1とみなす */
  885.             Options.istategaki = 1;
  886.         else
  887.             Options.istategaki = 0;
  888.         break;
  889.  
  890.     case '?':    option_help();    /* 返ってこないからbreakは要らない */
  891.  
  892.     default:    goto error;
  893.     }
  894.  
  895.     return;
  896.  
  897. error:
  898.     fprintf(stderr,    "不正なオプションです:%s\n\n"
  899.             "ヘルプを見るには ATHENA -?としてください.\n",s);
  900.     exit(1);
  901.  
  902. nomem:
  903.     fprintf(stderr,"メモリ不足です\n");
  904.     exit(1);
  905. }
  906. /*****************************************************************************/
  907. /*                            スタートアップ                                 */
  908. /*****************************************************************************/
  909. /*------------------------オプションの読みとりに使う変数---------------------*/
  910. static    FILE    *Responsefile = NULL;    /* レスポンスファイル               */
  911. static    char    *Argbuf;        /* 現在読み込んであるバッファの内容 */
  912.  
  913. static    char    **Argv;            /* コマンドラインのパラメータ       */
  914. /*--------------------行バッファからのトークンの切り出し---------------------*/
  915. /* gettoken()が返した値は、次に呼び出すまで有効。自由に書き換えてよい        */
  916. /*---------------------------------------------------------------------------*/
  917. #define    gettoken_init(s)    (Argbuf=(s))
  918.  
  919. static    char    *gettoken(void)
  920. {
  921.     int    isinsidequote = 0;
  922.     char    *ret;
  923.  
  924.     while    (isspace(*Argbuf))
  925.         Argbuf++;
  926.  
  927.     if    (*Argbuf=='\0')
  928.         return NULL;
  929.  
  930.     for    (ret=Argbuf ; ; Argbuf++)
  931.     {
  932.         char    c = *Argbuf;
  933.  
  934.         if    (c=='\0')
  935.         {
  936.             if    (isinsidequote)
  937.             {
  938.                     /* このエラーメッセージはLSI Cの */
  939.                     /* 標準のものに合わせた。        */
  940.                 fprintf(stderr,"Unmatched quote.\n");
  941.                 exit(1);
  942.             }
  943.             else
  944.                 break;
  945.         }
  946.  
  947.         if    (c=='"')
  948.             isinsidequote = !isinsidequote;
  949.  
  950.         if    (!isinsidequote && isspace(c))
  951.         {
  952.                 *Argbuf = '\0';
  953.                 break;
  954.         }
  955.  
  956.         if    (iskanji(c) || (isinsidequote && c=='^') )
  957.             Argbuf++;
  958.     }
  959.  
  960.     return ret;
  961. }
  962. /*------------------コマンドラインパラメータ入力の初期化---------------------*/
  963. static    void    init_arg(char **argv)
  964. {
  965.     Argv = argv+1;
  966.     gettoken_init(strdup(getenv("ATHENA")));
  967. }
  968. /*--------------------------パラメータの獲得---------------------------------*/
  969. /* この関数が返したバッファは、次にこの関数を呼び出すまで有効。              */
  970. /*---------------------------------------------------------------------------*/
  971. static    char    *getarg(void)
  972. {
  973.     char        *s;
  974.     static    char    *buf;
  975. rep1:
  976.     s = gettoken();
  977.     if    (s!=NULL)
  978.         return s;
  979. rep2:
  980.     if    (Responsefile==NULL)
  981.     {
  982.         if    (Argv[0]==NULL || Argv[0][0]!='@')
  983.             return *Argv++;
  984.         Responsefile = fopen(Argv[0]+1,"r");
  985.         if    (Responsefile==NULL)
  986.         {
  987.             fprintf(stderr,"ファイル%sがオープンできません\n",
  988.                                 Argv[0]+1);
  989.             exit(1);
  990.         }
  991.     }
  992.  
  993.     if    (fgets(buf,sizeof(buf),Responsefile)!=NULL)
  994.     {
  995.         gettoken_init(buf);
  996.         goto rep1;
  997.     }
  998.     else
  999.     {
  1000.         fclose(Responsefile);
  1001.         Responsefile = NULL;
  1002.         goto rep2;
  1003.     }
  1004. }
  1005. /*---------------------------メインルーチン----------------------------------*/
  1006. extern    int    main(int argc,char **argv)
  1007. {
  1008.     char    *s;
  1009.  
  1010.     fputs("テキスト印刷 8086|Printman/TEXT 'Athena' Version 1.00a\n\n",stderr);
  1011.  
  1012.     init_arg(argv);
  1013.  
  1014.     while    ((s=getarg())!=NULL)
  1015.     {
  1016.         if    (*s=='-')
  1017.             option(s);
  1018.         else
  1019.             xmain(s);
  1020.     }
  1021.  
  1022.     return 0;
  1023. }
  1024. /*-------------------------------コラム--------------------------------------*/
  1025. /* このプログラムは次のようなことを仮定している。                            */
  1026. /*     (1)半角の文字コードはASCIIあるいはそれを拡張した形式                  */
  1027. /*     (2)全角の文字コードはシフトJISやEUCのように、ASCIIと共存できる形式    */
  1028. /*        (ただし、シフトJIS以外のときはiskanji()の差し替えが必要)           */
  1029. /*     (3)定数EOFはwchar_tのどの有効な文字とも異なる                         */
  1030. /*     (4)charは8ビット                                                      */
  1031. /*     (5)unsignedとsignedの内部表現は同じ                                   */
  1032. /*        (計算の都合上(例えば1U<-1は1U<UINT_MAXとみなされ真となる)変数を    */
  1033. /*         signedで宣言しておきながら、sscanf()では"%u"を使用している)       */
  1034. /*--------------------------End of Athena.c----------------------------------*/
  1035.